package com.lambkit.plugin.qlexpress;

import cn.hutool.log.Log;
import com.lambkit.core.Lambkit;
import com.lambkit.core.LifecycleException;
import com.lambkit.core.plugin.Plugin;
import com.ql.util.express.ExpressRunner;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author yangyong(孤竹行)
 */
public class QLExpressPlugin extends Plugin {

    private static final Log log = Log.get(QLExpressPlugin.class);

    @Override
    public void start() throws LifecycleException {
        QLExpressManager qlExpressManager = Lambkit.get(QLExpressManager.class);
        try {
            ExpressRunner runner = createExpressRunner();
            qlExpressManager.setRunner(runner);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void stop() throws LifecycleException {
        super.stop();
        QLExpressManager qlExpressManager = Lambkit.get(QLExpressManager.class);
        qlExpressManager.getRunner().clearExpressCache();
    }

    /**
     * 支持 +,-,*,/,<,>,<=,>=,==,!=,<>【等同于!=】,%,mod【取模等同于%】,++,--,
     * in【类似sql】,like【sql语法】,&&,||,!,等操作符
     * 支持for，break、continue、if then else 等标准的程序控制逻辑
     * @throws Exception
     */
    public ExpressRunner createExpressRunner() throws Exception {
        ExpressRunner runner = new ExpressRunner(false, false);
        runner.addOperatorWithAlias("大于", ">", null);
        runner.addOperatorWithAlias("小于", "<", null);
        runner.addOperatorWithAlias("等于", "==", null);
        runner.addOperatorWithAlias("大于等于", ">=", null);
        runner.addOperatorWithAlias("小于等于", "<=", null);
        runner.addOperatorWithAlias("如果", "if", null);
        runner.addOperatorWithAlias("则", "then", null);
        runner.addOperatorWithAlias("否则", "else", null);

        Map<String, RuleHandler> beanMap = Lambkit.context().getBeanFactory().getBeansMapOfType(RuleHandler.class);
        if(beanMap != null) {
            beanMap.values().forEach(bean -> {
                Method[] methods = bean.getClass().getDeclaredMethods();

                for (Method method : methods) {
                    QlRule qlRule = method.getAnnotation(QlRule.class);

                    if (qlRule == null) {
                        continue;
                    }

                    try {
                        runner.addFunctionOfClassMethod(qlRule.methodName(), bean.getClass().getName(), method.getName(),
                                method.getParameterTypes(), null);
                    } catch (Exception ex) {
                        log.error("runner.addFunctionOfClassMethod", ex);
                    }
                }
            });
        }
        return runner;
    }
}
